using AutoMapper;
using StudentManagement.Application.DTOs;
using StudentManagement.Domain.Entities;
using StudentManagement.Domain.Repositories;

namespace StudentManagement.Application.Services;

public class ScoreService : IScoreService
{
    private readonly IScoreRepository _scoreRepository;
    private readonly IStudentRepository _studentRepository;
    private readonly ICourseRepository _courseRepository;
    private readonly IMapper _mapper;

    public ScoreService(IScoreRepository scoreRepository, IStudentRepository studentRepository, ICourseRepository courseRepository, IMapper mapper)
    {
        _scoreRepository = scoreRepository;
        _studentRepository = studentRepository;
        _courseRepository = courseRepository;
        _mapper = mapper;
    }

    public async Task<ScoreDTO> GetScoreByIdAsync(int id)
    {
        var score = await _scoreRepository.GetByIdAsync(id);
        if (score == null)
        {
            throw new Exception("成绩不存在");
        }

        return await MapScoreToDTOAsync(score);
    }

    public async Task<ScoreDTO> GetScoreByStudentAndCourseAsync(int studentId, int courseId)
    {
        var score = await _scoreRepository.GetScoreByStudentAndCourseAsync(studentId, courseId);
        if (score == null)
        {
            throw new Exception("成绩不存在");
        }

        return await MapScoreToDTOAsync(score);
    }

    public async Task<IEnumerable<ScoreDTO>> GetAllScoresAsync()
    {
        var scores = await _scoreRepository.GetAllAsync();
        return await MapScoresToDTOsAsync(scores);
    }

    public async Task<IEnumerable<ScoreDTO>> GetScoresByStudentIdAsync(int studentId)
    {
        var scores = await _scoreRepository.GetScoresByStudentIdAsync(studentId);
        return await MapScoresToDTOsAsync(scores);
    }

    public async Task<IEnumerable<ScoreDTO>> GetScoresByCourseIdAsync(int courseId)
    {
        var scores = await _scoreRepository.GetScoresByCourseIdAsync(courseId);
        return await MapScoresToDTOsAsync(scores);
    }

    public async Task<IEnumerable<ScoreDTO>> SearchScoresAsync(string keyword)
    {
        var scoresWithDetails = await _scoreRepository.GetScoresWithStudentAndCourseAsync();
        var filteredScores = scoresWithDetails.AsEnumerable();

        if (!string.IsNullOrWhiteSpace(keyword))
        {
            keyword = keyword.ToLower();
            filteredScores = filteredScores.Where(s =>
                s.Student.Name.ToLower().Contains(keyword) ||
                s.Student.StudentId.ToLower().Contains(keyword) ||
                s.Course.CourseName.ToLower().Contains(keyword) ||
                s.Course.CourseCode.ToLower().Contains(keyword) ||
                (s.TotalScore.HasValue && s.TotalScore.ToString().Contains(keyword)) ||
                (!string.IsNullOrEmpty(s.Grade) && s.Grade.ToLower().Contains(keyword))
            );
        }

        return await MapScoresToDTOsAsync(filteredScores);
    }

    public async Task<ScoreDTO> CreateScoreAsync(ScoreDTO scoreDTO)
    {
        // 验证学生是否存在
        if (!await _studentRepository.ExistsAsync(scoreDTO.StudentId))
        {
            throw new Exception("学生不存在");
        }

        // 验证课程是否存在
        if (!await _courseRepository.ExistsAsync(scoreDTO.CourseId))
        {
            throw new Exception("课程不存在");
        }

        // 验证成绩记录是否已存在
        var existingScore = await _scoreRepository.GetScoreByStudentAndCourseAsync(scoreDTO.StudentId, scoreDTO.CourseId);
        if (existingScore != null)
        {
            throw new Exception("该学生的此课程成绩已存在");
        }

        // 计算总成绩（如果期中考试和期末考试成绩都存在）
        if (scoreDTO.MidtermScore.HasValue && scoreDTO.FinalScore.HasValue)
        {
            scoreDTO.TotalScore = scoreDTO.MidtermScore.Value * 0.4m + scoreDTO.FinalScore.Value * 0.6m;
            // 根据总成绩计算等级
            scoreDTO.Grade = CalculateGrade(scoreDTO.TotalScore.Value);
        }

        var score = _mapper.Map<Score>(scoreDTO);
        score.UpdateDate = DateTime.Now;

        await _scoreRepository.AddAsync(score);

        return await MapScoreToDTOAsync(score);
    }

    public async Task<ScoreDTO> UpdateScoreAsync(int id, ScoreDTO scoreDTO)
    {
        var existingScore = await _scoreRepository.GetByIdAsync(id);
        if (existingScore == null)
        {
            throw new Exception("成绩不存在");
        }

        // 验证学生是否存在
        if (!await _studentRepository.ExistsAsync(scoreDTO.StudentId))
        {
            throw new Exception("学生不存在");
        }

        // 验证课程是否存在
        if (!await _courseRepository.ExistsAsync(scoreDTO.CourseId))
        {
            throw new Exception("课程不存在");
        }

        // 验证学生和课程组合是否已被其他成绩记录使用
        var scoreWithSameStudentCourse = await _scoreRepository.GetScoreByStudentAndCourseAsync(scoreDTO.StudentId, scoreDTO.CourseId);
        if (scoreWithSameStudentCourse != null && scoreWithSameStudentCourse.Id != id)
        {
            throw new Exception("该学生的此课程成绩已存在");
        }

        // 计算总成绩和等级
        if (scoreDTO.MidtermScore.HasValue && scoreDTO.FinalScore.HasValue)
        {
            scoreDTO.TotalScore = scoreDTO.MidtermScore.Value * 0.4m + scoreDTO.FinalScore.Value * 0.6m;
            scoreDTO.Grade = CalculateGrade(scoreDTO.TotalScore.Value);
        }

        // 更新成绩信息
        _mapper.Map(scoreDTO, existingScore);
        existingScore.UpdateDate = DateTime.Now;

        await _scoreRepository.UpdateAsync(existingScore);

        return await MapScoreToDTOAsync(existingScore);
    }

    public async Task DeleteScoreAsync(int id)
    {
        var score = await _scoreRepository.GetByIdAsync(id);
        if (score == null)
        {
            throw new Exception("成绩不存在");
        }

        await _scoreRepository.DeleteAsync(id);
    }

    public async Task<bool> ScoreExistsAsync(int id)
    {
        return await _scoreRepository.ExistsAsync(id);
    }

    public async Task<decimal?> GetAverageScoreByCourseIdAsync(int courseId)
    {
        // 验证课程是否存在
        if (!await _courseRepository.ExistsAsync(courseId))
        {
            throw new Exception("课程不存在");
        }

        return await _scoreRepository.GetAverageScoreByCourseIdAsync(courseId);
    }

    // 辅助方法：将Score实体映射到ScoreDTO，并填充学生和课程信息
    private async Task<ScoreDTO> MapScoreToDTOAsync(Score score)
    {
        var scoreDTO = _mapper.Map<ScoreDTO>(score);

        // 填充学生信息
        var student = await _studentRepository.GetByIdAsync(score.StudentId);
        if (student != null)
        {
            scoreDTO.StudentName = student.Name;
            scoreDTO.StudentIdNumber = student.StudentId;
        }

        // 填充课程信息
        var course = await _courseRepository.GetByIdAsync(score.CourseId);
        if (course != null)
        {
            scoreDTO.CourseName = course.CourseName;
            scoreDTO.CourseCode = course.CourseCode;
        }

        return scoreDTO;
    }

    // 辅助方法：将多个Score实体映射到ScoreDTO列表
    private async Task<IEnumerable<ScoreDTO>> MapScoresToDTOsAsync(IEnumerable<Score> scores)
    {
        var scoreDTOs = new List<ScoreDTO>();
        foreach (var score in scores)
        {
            scoreDTOs.Add(await MapScoreToDTOAsync(score));
        }
        return scoreDTOs;
    }

    // 辅助方法：根据分数计算等级
    private string CalculateGrade(decimal score)
    {
        if (score >= 90)
            return "优秀";
        else if (score >= 80)
            return "良好";
        else if (score >= 70)
            return "中等";
        else if (score >= 60)
            return "及格";
        else
            return "不及格";
    }
}